﻿using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Drawing;

namespace GArphics
{
    public class Renderer
    {
        public delegate void RenderEventHandler(object sender, RenderEventArgs e);
        public event RenderEventHandler ImageRendered;
        public event EventHandler AllRenderingDone;

        /// <summary>
        /// Queue for drawing the trees.
        /// </summary>
        private Queue<RenderData> _iTreesToDraw = new Queue<RenderData>();

        private List<RenderEngine> _oRenderEngines = new List<RenderEngine>();

        private int _iMaxRenderEngines = 1;

        public int MaxRenderEngines
        {
            get
            {
                return _iMaxRenderEngines;
            }
            set
            {
                if (value >= 1)
                    _iMaxRenderEngines = value;
            }
        }

        public Renderer()
        {
            InitializeRenderEngines();
        }

        /// <summary>
        /// Initializes the render-engines
        /// </summary>
        private void InitializeRenderEngines()
        {
            _oRenderEngines.Clear();    //Clearing the previous workers.

            for (int i = 0; i < _iMaxRenderEngines; i++)
            {
                RenderEngine oEngine = new RenderEngine2D();   //Creating a new worker
                oEngine.WorkerSupportsCancellation = false;         //Once the work has begun, it can't be stopped
                oEngine.WorkerReportsProgress = false;
                oEngine.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);  //Pointing the workers to the function which does the work
                oEngine.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);  //This function shall be called when the work has been completed.

                _oRenderEngines.Add(oEngine);
            }
        }

        /// <summary>
        /// Checks if there are any trees left to draw and draws them if necessary.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            if (_iTreesToDraw.Count > 0)    //are there any trees left to draw
            {
                try
                {
                    RenderData oData = _iTreesToDraw.Dequeue();    //taking a number of three which is to be drawn

                    (sender as RenderEngine).Render(oData);
                    e.Result = oData;
                }
                catch { }
            }
        }

        /// <summary>
        /// BackgroundWorker has completed the work. If the are still more trees to draw, new work is started.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (ImageRendered != null)
                ImageRendered(this, new RenderEventArgs(e.Result as RenderData));

            if (_iTreesToDraw.Count > 0)    //Have all the required work already been done?
                ((BackgroundWorker)sender).RunWorkerAsync();    //if not, running the worker again
            else
            {
                if (AllRenderingDone != null)
                    AllRenderingDone(this, new EventArgs());
            }
        }

        public void Start()
        {
            foreach (RenderEngine oEngine in _oRenderEngines)
            {
                oEngine.RunWorkerAsync();
            }
        }

        public void AddWork(RenderData Data)
        {
            _iTreesToDraw.Enqueue(Data);
        }

        public Bitmap RenderOne(Tree Tree, Size Size)
        {
            RenderData oData = new RenderData(Tree, Size, 0);

            _oRenderEngines[0].Render(oData);

            return oData.Image;
        }

        public void Stop()
        {
            _iTreesToDraw.Clear();
        }
    }
}
